;************* 功能说明 **************
;实验 6_1：
;1、读 ADC 测量外部电压.
;2、右边 4 位数码管显示测量的十六进制数值.
;4、使用 Timer0 的 16 位自动重装来产生 1ms 节拍, 进行动态扫描一位数码管。
;——————————————————————
;用 MCU 的 IO 方式控制 74HC595 驱动 8 位数码管位码， P6 控制段码。
;/************************ 用户定义宏 ******************************/
Fosc_KHZ EQU 24000 ;晶振 24000KHZ
STACK_POIRTER EQU 5FH ;堆栈开始地址
LED_TYPE EQU 000H ; 定义 LED 类型, 000H -- 共阴, 0FFH -- 共阳
Timer0_Reload EQU (65536 - Fosc_KHZ) ; Timer 0 中断频率, 1000 次/秒
DIS_DOT EQU 020H
DIS_BLACK EQU 010H
DIS_ EQU 011H
;*******************************************************************
ADC0_P10 EQU 00H
ADC1_P11 EQU 01H
ADC2_P54 EQU 02H
ADC3_P13 EQU 03H
ADC4_P14 EQU 04H
ADC5_P15 EQU 05H
ADC6_P16 EQU 06H
ADC7_P17 EQU 07H
ADC8_P00 EQU 08H
ADC9_P01 EQU 09H
ADC10_P02 EQU 0AH
ADC11_P03 EQU 0BH
ADC12_P04 EQU 0CH
ADC13_P05 EQU 0DH
ADC14_P06 EQU 0EH
ADC_PowerOn EQU (1 SHL 7) ;0000 0001 左移 7 位---1000 0000=0X80
ADC_RES_H4L8 EQU (1 SHL 5)
ADC_RES_H8L4 EQU 0
ADC_START EQU (1 SHL 6)
ADC_FLAG EQU (1 SHL 5) ;软件清零
;*******************************************************************
AUXR DATA 08EH
ADC_CONTR DATA 0BCH ;带 AD 系列 ADC_CONTR 地址
ADC_RES DATA 0BDH ;带 AD 系列 ADC_RES 地址
ADC_RESL DATA 0BEH ;带 AD 系列 ADC_RESL 地址
ADCCFG DATA 0DEH
P0M0 DATA 094H
P0M1 DATA 093H
P1M1 DATA 091H
P1M0 DATA 092H
P2M1 DATA 095H
P2M0 DATA 096H
P3M1 DATA 0B1H
P3M0 DATA 0B2H
P4M1 DATA 0B3H
P4M0 DATA 0B4H
P5M1 DATA 0C9H
P5M0 DATA 0CAH
P6M1 DATA 0CBH
P6M0 DATA 0CCH
P7M1 DATA 0E1H
P7M0 DATA 0E2H
P4 DATA 0C0H
P5 DATA 0C8H
P6 DATA 0E8H
P7 DATA 0F8H
;************* IO 口定义 **************/
P_HC595_SER BIT P4.4 ; //pin 14 SER data input
P_HC595_RCLK BIT P4.3 ; //pin 12 RCLk store (latch) clock
P_HC595_SRCLK BIT P4.2 ; //pin 11 SRCLK Shift data clock
;************* 本地变量声明 **************/
Flag0 DATA 20H
B_1ms BIT Flag0.0 ; 1ms 标志
LED8 DATA 30H ; 显示缓冲 30H ~ 37H
display_index DATA 38H ; 显示位索引
msecond_H DATA 39H ;
msecond_L DATA 3AH ;
BandgapH DATA 3BH ;
BandgapL DATA 3CH ;
ADC13_H DATA 3DH ;
ADC13_L DATA 3EH ;
;********************** 程序开始 *****************************************
ORG 0000H ;reset
LJMP F_Main
ORG 000BH ;1 Timer0 interrupt
LJMP F_Timer0_Interrupt
;******************** 主程序 **************************/
ORG 0100H ;reset
F_Main:
CLR A
MOV P0M1, A ;设置为准双向口
MOV P0M0, A
MOV P1M1, A ;设置为准双向口
MOV P1M0, A
MOV P2M1, A ;设置为准双向口
MOV P2M0, A
MOV P3M1, A ;设置为准双向口
MOV P3M0, A
MOV P4M1, A ;P4.0 设置成推挽输出，其余为准双向口
MOV P4M0, #01H
MOV P5M1, A ;设置为准双向口
MOV P5M0, A
MOV P6M1, A ;设置为推挽输出
MOV P6M0, #0FFH
MOV P7M1, A ;设置为准双向口
MOV P7M0, A
MOV SP, #STACK_POIRTER
MOV PSW, #0 ;选择第 0 组 R0~R7
;=================用户初始化程序 ================================
MOV display_index, #0
MOV R0, #LED8
MOV R2, #8
SETB P4.0 ;关闭 8 个流水灯
L_ClearLoop:
MOV @R0, #DIS_BLACK ;上电消隐
INC R0
DJNZ R2, L_ClearLoop
CLR TR0
ORL AUXR, #(1 SHL 7) ; Timer0_1T(); 定时器 0 不分频
ANL TMOD, #NOT 04H ; Timer0_AsTimer() ;定时器 0 为定时模式。
ANL TMOD, #NOT 03H ; Timer0_16bitAutoReload()
;方式 0,16 位自动重装模式
MOV TH0, #Timer0_Reload / 256 ;(65536-22118)/256=169=0XA9;
MOV TL0, #Timer0_Reload MOD 256 ;(65536-22118)MOD 256=154=0X9A
SETB ET0 ; Timer0_InterruptEnable();
SETB TR0 ; Timer0_Run();
SETB EA ; 打开总中断
LCALL F_ADC_config ; ADC 初始化
;=================== 主循环 ==================================
L_Main_Loop:
JNB B_1ms, L_Main_Loop ;1ms 未到
CLR B_1ms
;============ 检测300mS 是否到， 300mS转换一次============================
INC msecond_L ;msecond + 1
MOV A, msecond_L
JNZ $+4
INC msecond_H
CLR C
MOV A, msecond_L ;msecond - 300
SUBB A, #LOW 300
MOV A, msecond_H
SUBB A, #HIGH 300
JC L_Main_Loop ;if(msecond < 300), jmp
;================= 300ms 到 ====================================
MOV msecond_L, #0 ;if(msecond >= 1000)
MOV msecond_H, #0
MOV A, #ADC13_P05
LCALL F_Get_ADC12bitResult ;丢弃结果, 让内部的采样电容的电压等于输入值.
MOV A, #ADC13_P05
LCALL F_Get_ADC12bitResult ; 读外部电压 ADC, 查询方式做一次 ADC,
;返回值(R6 R7)就是 ADC 结果, == 4096 为错误
MOV ADC13_H, R6 ;保存 adc
MOV ADC13_L, R7
MOV A, R6
SWAP A
ANL A, #0x0F
MOV LED8+4, A
MOV A, R6
ANL A, #0x0F
MOV LED8+5, A
MOV A, R7
SWAP A
ANL A, #0x0F
MOV LED8+6, A
MOV A, R7
ANL A, #0x0F
MOV LED8+7, A
L_Quit_Check_300ms:
LJMP L_Main_Loop
;******************* ADC 配置 *******************************************/
F_ADC_config:
MOV ADC_CONTR, #ADC_PowerOn ;打开 ADC
ORL ADCCFG, #ADC_RES_H4L8 ;10 位 AD 结果的高 2 位放 ADC_RES的低 2 位，低 8 位在 ADC_RESL。
;adc 工作频率 SYSclk/2/1
ORL P0M1, #20H ; 把 ADC 口设置为高阻输入
ANL P0M0, #NOT 20H ; P1M1P1M0=10—高阻输入，用于 AD 输入
; SETB EADC ;中断允许
; SETB PADC ;优先级设置
RET
;//==================================================================
;// 函数: F_Get_ADC12bitResult
;// 描述: 查询法读一次 ADC 结果.
;// 参数: ACC: 选择要转换的 ADC.
;// 返回: (R6 R7) = 12 位 ADC 结果.
;// 版本:
;//==================================================================
;查询方式做一次 ADC, 返回值(R6 R7)就是 ADC 结果, 如= 4096 为错误
F_Get_ADC12bitResult:
MOV R7, A //channel
MOV ADC_RES, #0;
MOV ADC_RESL, #0;
MOV A, ADC_CONTR
ANL A, #0x80
ORL A, R7
ORL A, #ADC_START
MOV ADC_CONTR, A
NOP
NOP
NOP
NOP
MOV R3, #100
L_WaitAdcLoop:
MOV A, ADC_CONTR
JNB ACC.5, L_CheckAdcTimeOut;转换未完成跳转
ANL ADC_CONTR, #NOT ADC_FLAG ;清除完成标志
MOV A, ADC_RES ;12 位 AD 结果的高 4 位放 ADC_RES 的低 4 位，
;低 8 位在 ADC_RESL。
ANL A, #0FH
MOV R6, A ;高 2 位
MOV R7, ADC_RESL ;低 8 位
SJMP L_QuitAdc
L_CheckAdcTimeOut:
DJNZ R3, L_WaitAdcLoop
MOV R6, #HIGH 4096 ;超时错误,返回 4096,调用的程序判断
MOV R7, #LOW 4096
L_QuitAdc:
RET
; ****************** 显示相关程序 **************************************
T_DISPLAY: ;标准字库
; 0 1 2 3 4 5 6 7 8 9 A B C
DB 0C0H,0F9H,0A4H,0B0H,099H,092H,082H,0F8H,080H,090H,088H,083H,0C6H
; D E F
DB 0A1H,086H,08EH
; black - H L N o P U
DB 0FFH, 0BFH,089H,0C7H,0C8H,0A3H,08CH,0C1H
T_COM:
DB 80H,40H,20H,10H,08H,04H,02H,01H
;位码。实际为共阳数码管。
;===================== =======================================
; 函数: F_Send_595
; 描述: 向 HC595 发送一个字节子程序。
; 参数: ACC: 要发送的字节数据.
; 返回: none.
; 版本:
; 日期:
; 备注:
;================================================================
F_Send_595:
PUSH 02H ;R2 入栈
MOV R2, #8
L_Send_595_Loop:
RLC A
MOV P_HC595_SER,C
SETB P_HC595_SRCLK
CLR P_HC595_SRCLK
DJNZ R2, L_Send_595_Loop
POP 02H ;R2 出栈
RET
;===============================================================
; 函数: F_DisplayScan
; 描述: 显示扫描子程序。
; 参数: none.
; 返回: none.
; 版本:
; 日期:
; 备注:
;==============================================================
F_DisplayScan:
PUSH DPH ;DPH 入栈
PUSH DPL ;DPL 入栈
PUSH 00H ;R0 入栈
MOV A, #00H
LCALL F_Send_595 ;输出点阵位码，关闭点阵
MOV DPTR, #T_COM
MOV A, display_index
MOVC A, @A+DPTR
LCALL F_Send_595 ;输出数码管位码
CLR P_HC595_RCLK
NOP
SETB P_HC595_RCLK ;输出寄存器上升沿将移位输入的数据并行锁存
;到输出端
CLR P_HC595_RCLK ;锁存输出数据
MOV DPTR, #T_Display
MOV A, display_index
ADD A, #LED8
MOV R0, A ;每位显示的值
MOV A, @R0
MOVC A, @A+DPTR
MOV P6, A ;输出段码
INC display_index
MOV A, display_index
ANL A, #0F8H ; if(display_index >= 8)
JZ L_QuitDisplayScan ;display_index=0~7 跳
MOV display_index, #0; ;8 位结束回 0
L_QuitDisplayScan:
POP 00H ;R0 出栈
POP DPL ;DPL 出栈
POP DPH ;DPH 出栈
RET
;**************** 中断函数 ***************************************************
F_Timer0_Interrupt: ;Timer0 1ms 中断函数
PUSH PSW ;PSW 入栈
PUSH ACC ;ACC 入栈
LCALL F_DisplayScan ; 1ms 扫描显示一位
SETB B_1ms ; 1ms 标志
POP ACC ;ACC 出栈
POP PSW ;PSW 出栈
RETI
;*******************************************************************
END